﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmJournalRecordEventReceiver.h"
#include "StatusBarCtrl.h"

#include "JournalUtils.h"
#include "qevent.h"
#include "qobject.h"
#include "IJournalUiObject.h"
#include "IJournalUiEvent.h"
#include "CommandParameters.h"
#include "IControl.h"
#include "GbmpNew.h"

#include <QTableWidget>
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;
using namespace gcmp;

namespace
{
    bool IsQObjectOfDebugModeDlgType(const QObject *pObject)
    {
        if (nullptr == pObject)
        {
            // 允许为空，返回false。
            return false;
        }

        return pObject->metaObject()->className() == QString::fromStdWString(L"DebugModeDlg");
    }

    bool IsQObjectOfCmdManagerDlgType(const QObject* pObject)
    {
        if (nullptr == pObject)
        {
            // 允许为空，返回false。
            return false;
        }

        return pObject->metaObject()->className() == QString::fromStdWString(L"CmdManagerDlg");
    }

    bool IsQObjectDescendantOfDebugModeDlg(const QObject *pObject)
    {
        if (nullptr == pObject)
        {
            // 允许为空，返回false。
            return false;
        }

        // 自身是DebugModeDlg
        if (IsQObjectOfDebugModeDlgType(pObject))
        {
            return true;
        }

        // 自身是命令管理器
        if (IsQObjectOfCmdManagerDlgType(pObject))
        {
            return true;
        }

        QObject * pParent = pObject->parent();

        int level = 0;
        while (pParent && !IsQObjectOfDebugModeDlgType(pParent) && !IsQObjectOfCmdManagerDlgType(pParent))
        {
            pParent = pParent->parent();
            // 防止死循环
            if (++level >= 30/*当继承层次超过30层，就要考虑这样的设计是否合理了*/)
            {
                pParent = nullptr;
                break;
            }
        }

        return (pParent != nullptr);
    }

    bool IsQObjectDescendantWithNameSpace(const QMetaObject *pMetaObject, const QString& namespaceName)
    {
        if (!pMetaObject)
        {
            return false;
        }
        QString className = pMetaObject->className();
        DBG_WARN_AND_RETURN_UNLESS(!className.isEmpty(), false, L"pObject->metaObject()->className()不应该有为空的情况",L"GDMPLab",L"2024-03-30");
        if (className.startsWith(namespaceName + "::"))
        {
            return true;
        }
        else
        {
            return IsQObjectDescendantWithNameSpace(pMetaObject->superClass(), namespaceName);
        }
    }

    bool IsQObjectDescendantOfNameSpace(const QObject *pObject, const QString& namespaceName)
    {
        if (!pObject)
        {
            return false;
        }
        QString className = pObject->metaObject()->className();
        DBG_WARN_AND_RETURN_UNLESS(!className.isEmpty(), false, L"pObject->metaObject()->className()不应该有为空的情况",L"GDMPLab",L"2024-03-30");
        if (className.startsWith(namespaceName + "::"))
        {
            return true;
        }
        else
        {
            return IsQObjectDescendantOfNameSpace(pObject->parent(), namespaceName);
        }
    }

    bool IsQObjectDescendantOfThirdpartyWidget(const QObject *pObject,const QString& namespaceName)
    {
        if(nullptr == pObject)
        {
            //允许为空，返回false。
            return false;
        }
        if (IsQObjectDescendantWithNameSpace(pObject->metaObject(), namespaceName))
        {
            return true;
        }
        else
        {
            return(IsQObjectDescendantOfThirdpartyWidget(pObject->parent(),namespaceName));
        }
    }

    bool IsQObjectDescendantOfCustomWidget(const QObject *pObject, const char *name)
    {
        if (nullptr == pObject)
        {
            //允许为空，返回false。
            return false;
        }
        else
        {
            if (const QMetaObject * pMetaObject = pObject->metaObject())
                if (const char * pClassName = pMetaObject->className())
                    if (strcmp(pClassName, name) == 0)
                        return true;

            return(IsQObjectDescendantOfCustomWidget(pObject->parent(), name));
        }
    }

    bool IsScrollareaViewport(const QObject* const pObject)
    {
        if (pObject)
        {
            if (pObject->objectName() == QString("qt_scrollarea_viewport"))
            {
                return true;
            }
        }
        return false;
    }

    QTableWidget* GetParentTableWidget(const QObject *pObject)
    {
        if (!pObject)
        {
            return nullptr;
        }

        QTableWidget *pTableWidget = dynamic_cast<QTableWidget*>(pObject->parent());
        if (!pTableWidget)
        {
            pTableWidget = GetParentTableWidget(pObject->parent());
        }
        return pTableWidget;
    }

    bool FindCellWidgetIndex(const QObject* const pObject, int& row, int& column)
    {
        QTableWidget *pTableWidget = GetParentTableWidget(pObject);
        if (pTableWidget)
        {
            for (int i = 0; i < pTableWidget->rowCount(); ++i)
            {
                for (int j = 0; j < pTableWidget->columnCount(); ++j)
                {
                    if (pTableWidget->cellWidget(i, j) == pObject)
                    {
                        row = i;
                        column = j;
                        return true;
                    }
                }
            }
        }
        return false;
    }

    bool FindCellItemIndex(const QObject* const pObject, int scrollAreaPosX, int scrollAreaPosY, int& row, int& column)
    {
        if (IsScrollareaViewport(pObject))
        {
            QTableWidget *pTableWidget = GetParentTableWidget(pObject);
            if (pTableWidget)
            {
                row = pTableWidget->rowAt(scrollAreaPosY);
                column = pTableWidget->columnAt(scrollAreaPosX);
                if (row != -1 && column != -1)
                {
                    return true;
                }
            }
        }
        return false;
    }

    bool IsCellWidgetOfTableWidget(const QObject *pObject, const QEvent *pEvent, const QString &tableWidgetName, const QString rowIndex, const QString columnIndex)
    {
        QTableWidget *pTableWidget = GetParentTableWidget(pObject);
        if (!pObject || !pTableWidget)
        {
            return false;
        }

        if (tableWidgetName != pTableWidget->objectName())
        {
            return false;
        }

        int row = 0;
        int column = 0;
        if (!FindCellWidgetIndex(pObject, row, column))
        {
            const QMouseEvent *pMouseEvent = dynamic_cast<const QMouseEvent*>(pEvent);
            if (pMouseEvent && !FindCellItemIndex(pObject, pMouseEvent->x(), pMouseEvent->y(), row, column))
            {
                return false;
            }
        }

        QString rowHeaderData;
        QString columnHeaderData;
        if (pTableWidget->model())
        {
            rowHeaderData = pTableWidget->model()->headerData(row, Qt::Vertical, Qt::AccessibleDescriptionRole).toString();
            columnHeaderData = pTableWidget->model()->headerData(column, Qt::Horizontal, Qt::AccessibleDescriptionRole).toString();
        }

        if (rowHeaderData == rowIndex && columnHeaderData == columnIndex)
        {
            return true;
        }
        if (rowIndex.isEmpty() && columnHeaderData == columnIndex)
        {
            return true;
        }
        if (rowHeaderData == rowIndex && columnIndex.isEmpty())
        {
            return true;
        }
        if (rowIndex.isEmpty() && columnIndex.isEmpty())
        {
            return true;
        }
        return false;
    }

    bool IsOnSideToolBarDlg(const QObject *pObject)
    {
        if (pObject)
        {
            const QMetaObject* pMetaObject = pObject->metaObject();
            DBG_WARN_AND_RETURN_UNLESS(pMetaObject, false, L"pMetaObject为空",L"GDMPLab",L"2024-03-30");
            if (pMetaObject->className() == QString("gcmp::SideToolBarDlg"))
            {
                return true;
            }
            return IsOnSideToolBarDlg(pObject->parent());
        }
        return false;
    }
}

bool IsQObjectDescendantOfCustomWidgetByObjectName(const QObject *pObject, const QString &name)
{
    if (nullptr == pObject)
    {
        //允许为空，返回false。
        return false;
    }
    else if (pObject->objectName() == name)
    {
        return true;
    }
    else
    {
        return(IsQObjectDescendantOfCustomWidgetByObjectName(pObject->parent(), name));
    }
}

bool GmJournalRecordEventReceiver::ShouldIgnoreRecordQEvent(const IJournalUiObject *pIUIObject, const IJournalUiEvent *pIUIEvent) const
{
    //TODO:忽略Qt对象的事件
    DBG_WARN_AND_RETURN_UNLESS(pIUIObject && pIUIEvent, false, L"输入pIUIObject和pIUIEvent不应该有为空的情况",L"GDMPLab",L"2024-03-30");

    QObject *pObject = pIUIObject->GetUiObject().cast<QObject*>();
    DBG_WARN_AND_RETURN_UNLESS(pObject, false, L"输入pIUIObject中存储的控件对象类型不是QObject",L"GDMPLab",L"2024-03-30");
    QEvent *pEvent = pIUIEvent->GetUiEvent().cast<QEvent*>();
    DBG_WARN_AND_RETURN_UNLESS(pEvent, false, L"输入pIUIEvent中存储的事件对象类型不是QEvent",L"GDMPLab",L"2024-03-30");

    //ribbon上的控件
    if (!pObject->property(CTRL_ID).isNull())
    {
        return true;
    }

    if ((pEvent->type() == QEvent::MouseButtonPress || pEvent->type() == QEvent::MouseButtonRelease || pEvent->type() == QEvent::FocusOut) && IsCellWidgetOfTableWidget(pObject, pEvent, QString("GraphicsStyleTable"), QString(), QStringLiteral("材质")))
    {
        return true;
    }

    return false;
}

bool GmJournalRecordEventReceiver::ShouldIgnoreRecordQWidget(const IJournalUiObject *pIUIObject) const
{
    DBG_WARN_AND_RETURN_UNLESS(pIUIObject, false, L"输入pIUIObject不应该有为空的情况",L"GDMPLab",L"2024-03-30");

    QObject *pObject = pIUIObject->GetUiObject().cast<QObject*>();
    DBG_WARN_AND_RETURN_UNLESS(pObject, false, L"输入pIUIObject中存储的控件对象类型不是QObject",L"GDMPLab",L"2024-03-30");

    //ribbon上的控件
    if (!pObject->property(CTRL_ID).isNull())
    {
        return true;
    }

    // 不记录Definition管理的控件
    if (!pObject->property(IS_DEFINITION).isNull())
    {
        return true;
    }

    // 不记录DebugModeDlg
    if (IsQObjectDescendantOfDebugModeDlg(pObject))
    {
        return true;
    }

    //不记录MaterialSelectionDialog
    if(IsQObjectDescendantOfCustomWidget(pObject,"MaterialSelectionDialog"))
    {
        return true;
    }

    //不记录MaterialSettingInquiryDialog
    if(IsQObjectDescendantOfCustomWidget(pObject, "MaterialSettingInquiryDialog"))
    {
        return true;
    }

    //不记录ReplayJournalContentDlg
    if(IsQObjectDescendantOfCustomWidget(pObject,"ReplayJournalContentDlg"))
    {
        return true;
    }

    if (IsQObjectDescendantOfCustomWidget(pObject, "TimeRecordingDlg"))
    {
        return true;
    }
    //Ribbon上的控件不需要记录
    if (IsQObjectDescendantWithNameSpace(pObject->metaObject(), QString("Qtitan")))
    {
        return true;
    }
    if (IsQObjectDescendantOfNameSpace(pObject, QString("Qtitan")))
    {
        return true;
    }
    // FillPatternComboBoxList放在一个FillPatternComboBox中，由ComboBox级别进行日志记录
    if (IsQObjectDescendantOfCustomWidgetByObjectName(pObject, QString("FillPatternComboBoxList")))
    {
        return true;
    }
    //不记录SideToolBarDlg 
    if (IsOnSideToolBarDlg(pObject))
        return true;
    return false;
}

bool gcmp::GmJournalRecordEventReceiver::ShouldIgnoreVerifyQWidget(const IJournalUiObject *pIUIObject) const
{
    DBG_WARN_AND_RETURN_UNLESS(pIUIObject, false, L"输入pIUIObject不应该有为空的情况",L"GDMPLab",L"2024-03-30");

    QObject *pObject = pIUIObject->GetUiObject().cast<QObject*>();
    DBG_WARN_AND_RETURN_UNLESS(pObject, false, L"输入pIUIObject中存储的控件对象类型不是QObject",L"GDMPLab",L"2024-03-30");

    // 不验证引入的Qtitan及其子控件是否支持日志回放
    // Todo:第三方库上的控件不一定不需要支持，比如RibbonMainWindow上的控件，是有可能需要录制回放的
    if(IsQObjectDescendantOfThirdpartyWidget(pObject,QString("Qtitan")))
    {
        return true;
    }
    // 忽略掉继承自QWidget的自定义类
    QString className = pObject->metaObject()->className();
    if (className == "ApplyOrCancelWidget")
    {
        return true;
    }
    else if (className == "ElementEditHelper")
    {
        return true;
    }
    else if (className == "gcmp::QtBalloonTip")
    {
        return true;
    }
    else if (className == "QtNotificationBar")
    {
        return true;
    }
    else if (className == "QtNotificationHistoryPanel")
    {
        return true;
    }
    else if (className == "QtNotificationMessageBox")
    {
        return true;
    }
    else if (className == "PreviewColorWidget")
    {
        return true;
    }
    else if (className == "ViewerWidget")
    {
        return true;
    }
    else if (className == "BindFamParamToConstraintDlg")
    {
        return true;
    }
    else if (className == "DependencyGraphView")
    {
        return true;
    }
    else if (className == "GraphicsStyleTable")
    {
        return true;
    }
    else if (className == "ImportedObjectDocumentStylePage")
    {
        return true;
    }
    else if (className == "ImportedObjectModelViewStylePage")
    {
        return true;
    }
    else if (className == "QtLevelItemWidget")
    {
        return true;
    }
    else if (className == "TableEditorForMaterial")
    {
        return true;
    }
    else if (className == "TableEditorForTextStyle")
    {
        return true;
    }
    else if (className == "DrawingViewerWidget")
    {
        return true;
    }
    else if (className == "GLDRichTextEdit")
    {
        return true;
    }
    else if (className == "GLDRichTextEditFindAndReplaceWidget")
    {
        return true;
    }
    else if (className == "GLDRichTextEditTableValueTest")
    {
        return true;
    }
    else if (className == "QComboxGroups")
    {
        return true;
    }
    else if (className == "CComponentTypeEdit")
    {
        return true;
    }
    else if (className == "QtCharEdit")
    {
        return true;
    }
    else if (className == "QtColorEditWidget")
    {
        return true;
    }
    else if (className == "QtFontEditWidget")
    {
        return true;
    }
    else if (className == "QtAbstractPropertyBrowser")
    {
        return true;
    }
    else if (className == "QtBoolEdit")
    {
        return true;
    }
    else if (className == "QtKeySequenceEdit")
    {
        return true;
    }
    else if (className == "gcmp::OrthogonalGridGroupWidget")
    {
        return true;
    }
    else if (className == "IGMSExportFloorSelectionWidget")
    {
        return true;
    }
    else if (className == "IGMSExportRuleMatchingWidget")
    {
        return true;
    }
    else if (className == "GbmpLevelItemWidget")
    {
        return true;
    }

    return false;
}


